home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / BP7BUGS2.ZIP / TRASHSRC.ZIP / TRASHDET.PAS < prev    next >
Pascal/Delphi Source File  |  1993-01-03  |  7KB  |  308 lines

  1. {$define counter}  { Delete this define if you want to create TrashFix
  2.                      instead of TrashDet; it doesn't do the counting,
  3.                      so it's a bit smaller and faster. }
  4.  
  5.  
  6. program TrashDetector;
  7.  
  8. { TSR to detect hardware ISRs that trash the 386 extended registers }
  9.  
  10. uses
  11.   Dos;
  12.  
  13. type
  14.   regs = (reax,rebx,recx,redx,resi,redi,rebp,rfs,rgs);
  15.   TIntRec = record   { This record must be exactly 16 bytes long!!! }
  16.     oldisr : pointer;
  17.     counts : array[regs] of byte;
  18.     junk   : array[14..16] of byte;
  19.   end;
  20.  
  21.   TIntRecArray = array[0..15] of TIntRec;
  22.   PIntRecArray = ^TIntRecArray;
  23.  
  24. { Put the data in the code segment so we can discard the RTL when
  25.   we go resident. }
  26.  
  27. procedure InterruptRecs; assembler;
  28. { The first 8 records are in the PSP, so we need 128 bytes here.}
  29. asm
  30.   dd 1,2,3,4,5,6,7,8
  31.   dd 1,2,3,4,5,6,7,8
  32.   dd 1,2,3,4,5,6,7,8
  33.   dd 1,2,3,4,5,6,7
  34.   db 1,2,3
  35. end;  { RET is the last byte }
  36.  
  37. procedure signature; assembler;
  38. asm
  39.   db 'xxxx is the Trash Detector!'   { "xxxx" is replaced with "This"
  40.                                        at run-time, to avoid false alarms. }
  41. end;
  42.  
  43. const
  44.   { These constants allow us to code 386-specific instructions }
  45.   Op32   = $66;
  46.   PushFS = $A00F;
  47.   PushGS = $A80F;
  48.   PopFS  = $A10F;
  49.   PopGS  = $A90F;
  50.   MovAXFS= $E08C;
  51.   MovAXGS= $E88C;
  52.  
  53.   PtrOfs = 15*sizeof(TIntRec) - $80;
  54.   CountOfs = PtrOfs + 4;
  55.  
  56.  
  57. procedure CountingISR; far; assembler;
  58. { This ISR counts all cases where the extended registers get trashed.
  59.   Use this one if you want to run TrashRep.  Uses 26 bytes of stack
  60.   space. }
  61. asm
  62.   push bp
  63.   mov bp,sp
  64.  
  65.   db Op32; push ax
  66.   pop ax
  67.   db Op32; push bx
  68.   pop bx
  69.   db Op32; push cx
  70.   pop cx
  71.   db Op32; push dx
  72.   pop dx
  73.   db Op32; push si
  74.   pop si
  75.   db Op32; push di
  76.   pop di
  77.   db Op32; push bp
  78.   pop bp
  79.   dw PushFS
  80.   dw PushGS
  81.  
  82.   push word ptr [bp+6]           { old flags }
  83.   mov bp,[bp]                    { and restore BP }
  84.   call dword ptr cs:InterruptRecs[PtrOfs]
  85.   push ax
  86.   pushf
  87.   pop ax                     { Now flags are in AX }
  88.  
  89.   push bp                    { Save the ISR's BP }
  90.   mov bp,sp                  { Set up our frame again }
  91.   add bp,22
  92.   mov word ptr [bp+6],ax      { This way flags on our return will be
  93.                                    as the old ISR returned them. }
  94.   pop ax
  95.   mov word ptr [bp],ax        { as will BP }
  96.  
  97.   { AX is still on the stack }
  98.   dw MovAXGS
  99.   cmp word ptr[BP - 18],ax
  100.   je @l7
  101.   inc byte ptr cs:InterruptRecs[CountOfs+rgs]
  102. @l7:
  103.  
  104.   dw MovAXFS
  105.   cmp word ptr[BP - 16],ax
  106.   je @l8
  107.   inc byte ptr cs:InterruptRecs[CountOfs+rfs]
  108. @l8:
  109.  
  110.   pop ax
  111.   dw PopGS
  112.   dw PopFS
  113.  
  114.   push bp
  115.   db Op32; cmp word ptr[BP - 16],bp
  116.   je @l9
  117.   inc byte ptr cs:InterruptRecs[CountOfs+rebp]
  118. @l9:
  119.   db Op32; pop bp
  120.  
  121.   push di
  122.   db Op32; cmp word ptr[BP - 14],di
  123.   je @l1
  124.   inc byte ptr cs:InterruptRecs[CountOfs+redi]
  125. @l1:
  126.   db Op32; pop di
  127.  
  128.   push si
  129.   db Op32; cmp word ptr[BP - 12],si
  130.   je @l2
  131.   inc byte ptr cs:InterruptRecs[CountOfs+resi]
  132. @l2:
  133.   db Op32; pop si
  134.  
  135.   push dx
  136.   db Op32; cmp word ptr[BP - 10],dx
  137.   je @l3
  138.   inc byte ptr cs:InterruptRecs[CountOfs+redx]
  139. @l3:
  140.   db Op32; pop dx
  141.  
  142.   push cx
  143.   db Op32; cmp word ptr[BP - 8],cx
  144.   je @l4
  145.   inc byte ptr cs:InterruptRecs[CountOfs+recx]
  146. @l4:
  147.   db Op32; pop cx
  148.  
  149.   push bx
  150.   db Op32; cmp word ptr[BP - 6],bx
  151.   je @l5
  152.   inc byte ptr cs:InterruptRecs[CountOfs+rebx]
  153. @l5:
  154.   db Op32; pop bx
  155.  
  156.   push ax
  157.   db Op32; cmp word ptr[BP - 4],ax
  158.   je @l6
  159.   inc byte ptr cs:InterruptRecs[CountOfs+reax]
  160. @l6:
  161.   db Op32; pop ax
  162.  
  163.   pop bp
  164.   iret
  165. end;
  166.  
  167. procedure FixupISR; far; assembler;
  168. { This ISR saves and restores the high word of EAX,EBX,ECX,EDX,ESI, and EDI.
  169.   Use it to fix up a bad handler.  Uses 26 bytes of stack space. }
  170. asm
  171.   push bp
  172.   mov bp,sp
  173.  
  174.   db Op32; push ax
  175.   pop ax
  176.   db Op32; push bx
  177.   pop bx
  178.   db Op32; push cx
  179.   pop cx
  180.   db Op32; push dx
  181.   pop dx
  182.   db Op32; push si
  183.   pop si
  184.   db Op32; push di
  185.   pop di
  186.   db Op32; push bp
  187.   pop bp
  188.   dw PushFS
  189.   dw PushGS
  190.  
  191.   push word ptr [bp+6]           { old flags }
  192.   mov bp,[bp]                    { and restore BP }
  193.   call dword ptr cs:InterruptRecs[PtrOfs]
  194.   push ax
  195.   pushf
  196.   pop ax                     { Now flags are in AX }
  197.  
  198.   push bp                    { Save the ISR's BP }
  199.   mov bp,sp                  { Set up our frame again }
  200.   add bp,22
  201.   mov word ptr [bp+6],ax      { This way flags on our return will be
  202.                                    as the old ISR returned them. }
  203.   pop ax
  204.   mov word ptr [bp],ax        { as will BP }
  205.  
  206.   pop ax
  207.   dw PopGS
  208.   dw PopFS
  209.   push bp
  210.   db Op32; pop bp
  211.   push di
  212.   db Op32; pop di
  213.   push si
  214.   db Op32; pop si
  215.   push dx
  216.   db Op32; pop dx
  217.   push cx
  218.   db Op32; pop cx
  219.   push bx
  220.   db Op32; pop bx
  221.   push ax
  222.   db Op32; pop ax
  223.  
  224.   pop bp
  225.   iret
  226. end;
  227.  
  228. procedure Marker; assembler;
  229. asm
  230. end;
  231.  
  232. var
  233.   IntRecs : PIntRecArray;
  234.   int,irq : byte;
  235.  
  236. procedure InstallHandler;
  237. var
  238.   addr : pointer;
  239.   segmod : byte;
  240. begin
  241.   GetIntVec(int,IntRecs^[irq].OldIsr);
  242.   segmod := 15-irq;
  243. {$ifdef counter}
  244.   Addr := Ptr(Seg(CountingISR)-segmod, Ofs(CountingISR)+16*segmod);
  245. {$else}
  246.   Addr := Ptr(Seg(FixupISR)-segmod, Ofs(FixupISR)+16*segmod);
  247. {$endif}
  248.   SetIntVec(int,Addr);
  249. end;
  250.  
  251. const
  252.   sigstart : longint = $73696854; { "This" }
  253.  
  254. var
  255.   paras : word;
  256.   envseg : word;
  257. begin
  258. {$ifdef counter}
  259.   MemL[Seg(Signature):Ofs(Signature)] := sigstart;  { Complete the signature }
  260.   write('TrashDet - Detects');
  261. {$else}
  262.   write('TrashFix - Corrects');
  263. {$endif}
  264.   writeln(' trashing of extended registers during interrupt servicing');
  265.   writeln('Written by D.J. Murdoch, January, 1993, for the public domain');
  266.  
  267.   if test8086 < 2 then
  268.     writeln('Program only works (and is only needed) on a 386 or higher.')
  269.   else
  270.   begin
  271.     SwapVectors;
  272.  
  273.     IntRecs := Ptr(PrefixSeg,$80);
  274.     FillChar(IntRecs^,sizeof(IntRecs^),0);
  275.  
  276.     for int := 8 to $F do
  277.     begin
  278.       irq := int-8;
  279.       installhandler;
  280.     end;
  281.     for int := $70 to $77 do
  282.     begin
  283.       irq := int-$70+8;
  284.       installhandler;
  285.     end;
  286.  
  287.     { Release the environment }
  288.     envseg := memw[Prefixseg:$2C];
  289.     asm
  290.       mov ah,$49
  291.       mov es,envseg
  292.       int $21
  293.     end;
  294.  
  295.     paras := (ofs(Marker) + 15) div 16 + 16;
  296.  
  297.     write('Going resident...');
  298. {$ifdef counter}
  299.     writeln('run TrashRep for report.');
  300. {$endif}
  301.     asm
  302.       mov ax,$3100
  303.       mov dx,paras
  304.       int $21
  305.     end;
  306.     writeln('Failed!!');
  307.   end;
  308. end.